package com.jokins.common.util.passwore;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;

/**
 * 〈〉<br>
 * 前后台加密方法
 *
 * @author Mr.Wang
 * @create 2025/2/5
 */
public class SaltPasswordUtil {
    // 迭代次数，增加破解难度
    private static final int ITERATIONS = 10000;
    // 生成的密钥长度
    private static final int KEY_LENGTH = 256;

    private static final String salt = "LikeProjects";

    /**
     * 对密码进行加密
     *
     * @param password 原始密码
     * @param salt     盐值
     * @return 加密后的密码
     */
    public static String encryptPassword(String password, String salt) {
        try {
            // 将密码转换为字符数组
            char[] passwordChars = password.toCharArray();
            // 将盐值从 Base64 编码转换为字节数组
            byte[] saltBytes = Base64.getDecoder().decode(salt);

            // 使用 PBKDF2WithHmacSHA256 算法进行加密
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            // 创建 PBEKeySpec 对象，包含密码、盐值、迭代次数和密钥长度
            PBEKeySpec spec = new PBEKeySpec(passwordChars, saltBytes, ITERATIONS, KEY_LENGTH);
            // 生成加密后的密钥
            byte[] hash = skf.generateSecret(spec).getEncoded();

            // 将加密后的字节数组进行 Base64 编码，转换为字符串返回
            return Base64.getEncoder().encodeToString(hash);
        } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
            // 若出现异常，打印堆栈跟踪信息并返回 null
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 生成随机盐值
     *
     * @return 随机生成的盐值（Base64 编码后的字符串）
     */
    public static String generateSalt() {
        // 使用 SecureRandom 生成随机数
        SecureRandom random = new SecureRandom();
        // 盐值长度为 16 字节
        byte[] salt = new byte[16];
        // 生成随机盐值
        random.nextBytes(salt);
        // 将盐值进行 Base64 编码，转换为字符串返回
        return Base64.getEncoder().encodeToString(salt);
    }

    /**
     * 校验加密密码
     *
     * @param inputPassword     输入的原始密码
     * @param salt              盐值
     * @param encryptedPassword 加密后的密码
     * @return 密码是否匹配
     */
    public static boolean verifyPassword(String inputPassword, String salt, String encryptedPassword) {
        try {
            // 对输入的密码进行加密
            String newEncryptedPassword = encryptPassword(inputPassword, salt);
            // 比较加密后的密码是否相等
            return newEncryptedPassword != null && newEncryptedPassword.equals(encryptedPassword);
        } catch (Exception e) {
            // 若出现异常，打印堆栈跟踪信息并返回 false
            e.printStackTrace();
            return false;
        }
    }

    public static void main(String[] args) {
        // 示例密码
        String password = "Passw0rd";
        // 加密密码
        String encryptedPassword = encryptPassword(password, salt);

        System.out.println("Original Password: " + password);
        System.out.println("Salt: " + salt);
        System.out.println("Encrypted Password: " + encryptedPassword);

        // 校验密码
        boolean isPasswordCorrect = verifyPassword(password, salt, encryptedPassword);
        System.out.println("Password is correct: " + isPasswordCorrect);

        // 校验错误密码
        boolean isWrongPassword = verifyPassword("wrongPassword", salt, encryptedPassword);
        System.out.println("Wrong password check: " + isWrongPassword);
    }
}